Packages
library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr 1.1.4 ✔ readr 2.1.5
## ✔ forcats 1.0.0 ✔ stringr 1.5.1
## ✔ ggplot2 3.5.1 ✔ tibble 3.2.1
## ✔ lubridate 1.9.3 ✔ tidyr 1.3.1
## ✔ purrr 1.0.2
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(terra)
## Warning: package 'terra' was built under R version 4.4.1
## terra 1.8.10
##
## Attaching package: 'terra'
##
## The following object is masked from 'package:tidyr':
##
## extract
library(sf)
## Warning: package 'sf' was built under R version 4.4.1
## Linking to GEOS 3.11.0, GDAL 3.5.3, PROJ 9.1.0; sf_use_s2() is TRUE
library(leaflet)
library(leaflet.extras)
## Warning: package 'leaflet.extras' was built under R version 4.4.1
Leaflet is….
…a Javascript library with an API we can access in R.
Wait, that’s a LOT of jargon. Can we add some clarity?
A simple setup
m <- leaflet()
m
What do you get?
Let’s try again
m <- leaflet() %>%
addTiles()
m
And now? What do you see?
Let’s build on that
m <- leaflet() %>%
addTiles() %>% # Add default OpenStreetMap map tiles
addMarkers(lng = -81.350903, lat = 41.150377, popup="Our McGilvrey Hall GIS Lab")
m
What about now?
Create some data to plot. Let’s break this down a bit. What am I trying to do?
# First let's define a color palette we can sample from - this is only really necessary for the demo
mypal <- RColorBrewer::brewer.pal(12, "Set3")
# start with a data frame
df <- data.frame(
lat = rnorm(100) * 2 + 41,
lng = rnorm(100) * 2 - 81.5,
size = runif(100, 5, 20),
color = sample(mypal, 100, replace = T)
)
# then add the data frame to a leaflet map
m2 <- leaflet(df) %>% addTiles()
m2
What do you get? Why?
How can we interrogate the properties/attributes of an object?
The $ operator
m2$x
## $options
## $options$crs
## $crsClass
## [1] "L.CRS.EPSG3857"
##
## $code
## NULL
##
## $proj4def
## NULL
##
## $projectedBounds
## NULL
##
## $options
## named list()
##
## attr(,"class")
## [1] "leaflet_crs"
##
##
## $calls
## $calls[[1]]
## $calls[[1]]$method
## [1] "addTiles"
##
## $calls[[1]]$args
## $calls[[1]]$args[[1]]
## [1] "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
##
## $calls[[1]]$args[[2]]
## NULL
##
## $calls[[1]]$args[[3]]
## NULL
##
## $calls[[1]]$args[[4]]
## $calls[[1]]$args[[4]]$minZoom
## [1] 0
##
## $calls[[1]]$args[[4]]$maxZoom
## [1] 18
##
## $calls[[1]]$args[[4]]$tileSize
## [1] 256
##
## $calls[[1]]$args[[4]]$subdomains
## [1] "abc"
##
## $calls[[1]]$args[[4]]$errorTileUrl
## [1] ""
##
## $calls[[1]]$args[[4]]$tms
## [1] FALSE
##
## $calls[[1]]$args[[4]]$noWrap
## [1] FALSE
##
## $calls[[1]]$args[[4]]$zoomOffset
## [1] 0
##
## $calls[[1]]$args[[4]]$zoomReverse
## [1] FALSE
##
## $calls[[1]]$args[[4]]$opacity
## [1] 1
##
## $calls[[1]]$args[[4]]$zIndex
## [1] 1
##
## $calls[[1]]$args[[4]]$detectRetina
## [1] FALSE
##
## $calls[[1]]$args[[4]]$attribution
## [1] "© <a href=\"https://openstreetmap.org/copyright/\">OpenStreetMap</a>, <a href=\"https://opendatacommons.org/licenses/odbl/\">ODbL</a>"
##
##
##
##
##
## attr(,"leafletData")
## lat lng size color
## 1 40.74603 -83.45007 14.868927 #FFFFB3
## 2 40.20238 -83.95451 14.550825 #B3DE69
## 3 40.98750 -80.41588 6.697696 #80B1D3
## 4 39.10575 -79.84838 11.197219 #FB8072
## 5 44.50473 -79.46529 15.629754 #FFFFB3
## 6 38.86650 -82.54185 14.863234 #FDB462
## 7 44.36183 -80.83767 7.206468 #FFFFB3
## 8 42.03602 -81.11311 19.936633 #CCEBC5
## 9 41.39381 -79.46374 17.007305 #FDB462
## 10 42.48659 -82.08278 6.493354 #FB8072
## 11 40.80987 -83.19531 7.996221 #FFFFB3
## 12 39.86277 -77.69739 15.482108 #FB8072
## 13 44.65650 -84.85271 6.098189 #FFED6F
## 14 36.94411 -79.84225 13.999388 #FDB462
## 15 41.01350 -82.37728 6.456319 #FB8072
## 16 39.57375 -81.48592 10.648559 #8DD3C7
## 17 43.30297 -81.79619 11.616977 #FDB462
## 18 41.89682 -82.75958 17.169873 #BEBADA
## 19 41.28814 -83.07938 12.344856 #BC80BD
## 20 38.45777 -82.99757 17.311140 #CCEBC5
## 21 37.70709 -82.26975 17.806325 #FDB462
## 22 38.52106 -82.91888 10.976237 #FFED6F
## 23 40.06122 -79.84932 18.684877 #FFED6F
## 24 40.50728 -81.36894 16.058527 #CCEBC5
## 25 39.64461 -80.48374 11.757635 #D9D9D9
## 26 44.41391 -79.83604 6.791354 #FB8072
## 27 41.81229 -80.86726 12.304616 #80B1D3
## 28 42.48402 -79.62170 11.080573 #FFED6F
## 29 43.31210 -80.94017 18.126557 #FCCDE5
## 30 42.43452 -79.15316 13.598137 #FB8072
## 31 40.52948 -79.75909 17.280855 #FB8072
## 32 40.41377 -79.91344 10.574191 #B3DE69
## 33 40.25365 -81.38667 19.672723 #8DD3C7
## 34 43.97015 -80.59741 17.916000 #FB8072
## 35 41.59492 -82.07272 11.451747 #FCCDE5
## 36 40.40464 -79.13279 12.413794 #FFFFB3
## 37 37.99826 -79.51608 8.264504 #FFED6F
## 38 43.21010 -81.53139 5.097577 #80B1D3
## 39 43.50818 -79.66151 7.496173 #8DD3C7
## 40 42.40478 -77.73546 11.907850 #FFFFB3
## 41 39.36782 -77.01632 12.054958 #BEBADA
## 42 40.29865 -82.38083 14.969194 #BC80BD
## 43 41.44668 -85.48388 10.018350 #B3DE69
## 44 40.88648 -83.96119 9.522050 #FFFFB3
## 45 40.54576 -79.72585 11.245230 #FCCDE5
## 46 40.10957 -80.15598 16.897455 #B3DE69
## 47 40.55463 -82.66070 6.504108 #FDB462
## 48 38.38378 -81.80725 9.853867 #D9D9D9
## 49 42.03522 -80.76773 8.670518 #80B1D3
## 50 38.35694 -80.94591 9.284026 #FCCDE5
## 51 40.16155 -83.76884 15.224541 #FDB462
## 52 41.05248 -81.26068 8.927646 #80B1D3
## 53 41.69041 -79.44301 9.838585 #80B1D3
## 54 38.05285 -80.92638 6.394559 #BEBADA
## 55 39.63057 -86.17669 13.859316 #FDB462
## 56 39.75909 -81.29235 11.423585 #BEBADA
## 57 40.62700 -82.19091 15.393758 #FFED6F
## 58 39.57994 -83.38346 14.177956 #FFED6F
## 59 40.50729 -82.04547 7.566029 #FFFFB3
## 60 39.28100 -82.79194 16.650551 #FDB462
## 61 40.10139 -80.74254 9.426662 #80B1D3
## 62 42.09426 -82.32802 15.803093 #CCEBC5
## 63 45.09770 -77.17280 16.566673 #80B1D3
## 64 40.74408 -81.56063 12.441043 #CCEBC5
## 65 41.60859 -82.54916 17.646481 #BC80BD
## 66 41.78560 -79.56002 16.197787 #80B1D3
## 67 41.53633 -82.00549 17.957299 #8DD3C7
## 68 40.28095 -81.64869 14.459434 #FFED6F
## 69 44.54700 -81.09271 19.898664 #80B1D3
## 70 41.29158 -82.17957 5.698990 #FB8072
## 71 39.58424 -79.30207 17.209757 #D9D9D9
## 72 41.20083 -81.68176 5.039658 #BEBADA
## 73 40.98879 -82.89103 16.068044 #80B1D3
## 74 42.66432 -78.40134 5.706808 #FFED6F
## 75 40.96343 -81.55521 14.731461 #FB8072
## 76 39.30024 -82.58334 14.519423 #CCEBC5
## 77 38.83713 -80.61441 19.572098 #FFED6F
## 78 40.24927 -82.65505 13.563011 #D9D9D9
## 79 40.29989 -79.26816 18.643867 #FB8072
## 80 41.99950 -80.56377 9.462960 #8DD3C7
## 81 39.38699 -80.54877 5.027068 #FCCDE5
## 82 41.84487 -84.68819 19.769341 #BC80BD
## 83 37.38107 -81.29843 15.476084 #BEBADA
## 84 41.31889 -82.17798 19.927976 #FDB462
## 85 43.69980 -80.43696 10.123885 #FFED6F
## 86 39.61725 -80.69869 9.010128 #B3DE69
## 87 42.33963 -79.91979 19.147547 #FFED6F
## 88 39.78807 -82.03843 9.966668 #FDB462
## 89 42.50417 -81.00021 8.954779 #BEBADA
## 90 40.12446 -82.79217 14.121531 #8DD3C7
## 91 39.91140 -80.72159 9.905358 #CCEBC5
## 92 40.34544 -80.11924 15.923880 #BC80BD
## 93 41.38325 -82.82173 7.905780 #FDB462
## 94 41.51646 -78.67355 19.341440 #FB8072
## 95 43.03387 -82.51782 5.318999 #BC80BD
## 96 37.89447 -83.81203 6.779462 #BC80BD
## 97 41.46053 -78.43137 13.795615 #CCEBC5
## 98 37.46981 -82.65104 7.482956 #BEBADA
## 99 42.63798 -83.79103 14.194038 #FFFFB3
## 100 41.15436 -82.08332 8.673613 #FDB462
What do the data look like?
Let’s try again to visualize it. Again, break down the code first
# first one
m2 %>% addCircleMarkers(radius = ~size, color = ~color, fill = FALSE)
## Assuming "lng" and "lat" are longitude and latitude, respectively
# second one
m2 %>% addCircleMarkers(radius = runif(100, 4, 10), color = c('red'))
## Assuming "lng" and "lat" are longitude and latitude, respectively
What happened this time???
Let’s add some more tiles
# Let's check out some other tiles
m <- leaflet() %>% setView(lng = -81.34, lat = 41.145, zoom = 14)
m %>% addTiles()
# third party tiles using addProvider() function
m %>% addProviderTiles(providers$Stadia.StamenToner)
m %>% addProviderTiles(providers$CartoDB.Positron)
m %>% addProviderTiles(providers$CartoDB.DarkMatter)
m %>% addProviderTiles(providers$Esri.NatGeoWorldMap)
Give it a shot. What do you like?
parks <- sf::read_sf("../data/static_mapping/oh_parks.gpkg") %>%
sf::st_transform(., "EPSG:4326") # transform to WGS84 to make Leaflet happy
# set up the map, zoom out a bit
mp <- leaflet(data = parks) %>% setView(lng = -81.34, lat = 41.145, zoom = 10)
mp %>% addTiles() %>%
addPolygons(popup = ~NAME, label = ~NAME)
What’s the difference between popup and label?
Who wants to help break down this code?
portage_streams <- sf::read_sf("../data/static_mapping/tl_2022_39133_linearwater/tl_2022_39133_linearwater.shp") %>%
sf::st_transform(., "EPSG:4326") # transform to WGS84 to make Leaflet happy
leaflet(data = portage_streams) %>%
setView(lng = -81.34, lat = 41.145, zoom = 10) %>%
addTiles() %>%
addPolylines(., color = "blue",
popup = ~paste0(FULLNAME, ": ", LINEARID))
What happened?
(Note, there’s a difference here)
m.both <- leaflet() %>%
setView(lng = -81.34, lat = 41.145, zoom = 10) %>%
addProviderTiles(providers$Esri.NatGeoWorldMap) %>%
addPolygons(data = parks, popup = ~NAME, label = ~NAME, color = "green") %>%
addPolylines(data = portage_streams, color = "blue",
popup = ~paste0(FULLNAME, ": ", LINEARID))
m.both
leaflet.extras package